﻿using System;

namespace OverloadAndOverrideApp
{
    /*
     
2、重写(override):子类中为满足自己的需要来重复定义某个方法的不同实现，需要用 override 关键字，被重写的方法必须是虚方法，用的是 virtual 关键字。它的特点是(三个相同):

相同的方法名
相同的参数列表
相同的返回值

     */
    class Animal
    {
        // 虚方法：即为基类中定义的允许在派生类中重写的方法，使用virtual关键字定义。如：
        public virtual void EatFood()
        {
            Console.WriteLine("Animal吃东西");
        }
    }

    class Cat : Animal
    {
        public override void EatFood()
        {
            Console.WriteLine("Cat吃东西");
        }
    }

    // 4、抽象方法：在基类中定义的并且必须在派生类中重写的方法，使用 abstract 关键字定义。如：
    public abstract class Biology
    {
        public abstract void Live();
    }

    public class Animal1 : Biology
    {
        public override void Live()
        {
            Console.WriteLine("Animal重写的抽象方法");
        }
    }

    public class TestA
    {
        //public abstract void Live();// 注意：抽象方法只能在抽象类中定义，如果不在抽象类中定义，则会报出如下错误：
    }

    public class TestParent
    {
        public void Sleep()
        {
            Console.WriteLine("TestParent Sleep");
        }
    }

    public class TestChildren :TestParent
    {
        /*
         注意：
（1）隐藏方法不但可以隐藏基类中的虚方法，而且也可以隐藏基类中的非虚方法。
（2）隐藏方法中父类的实例调用父类的方法，子类的实例调用子类的方法。
（3）和上一条对比：重写方法中子类的变量调用子类重写的方法，父类的变量要看这个父类引用的是子类的实例还是本身的实例，如果引用的是父类的实例那么调用基类的方法，如果引用的是派生类的实例则调用派生类的方法。
         */
        public new void Sleep()
        {
            Console.WriteLine("TestChildren Sleep");
        }
    }

    class Program
    {
        /*
1、重载(overload): 在同一个作用域(一般指一个类)的两个或多个方法函数名相同，参数列表不同的方法叫做重载，它们有三个特点(俗称两必须一可以):

 方法名必须相同
 参数列表必须不相同
 返回值类型可以不相同
         */
        public static void Sleep()
        {
            Console.WriteLine("Animal睡觉");
        }

        public static int Sleep(int time)
        {
            Console.WriteLine("Animal[0]点睡觉,", time);
            return time;
        }

        static void Main(string[] args)
        {
            // 注意：虚方法也可以被直接调用。如：
            Animal a = new Animal();
            a.EatFood();
            Console.ReadKey();
        }
    }
}

/*
 
C# 多态性

多态：一个接口多个功能。

静态多态性：编译时发生函数响应（调用）；

动态多态性：运行时发生函数响应。

静态绑定（早期绑定）：编译时函数和对象的连接机制。 两种技术实现静态多态性：函数重载/运算符重载。

函数重载：在同一范围内对相同函数名有多个定义，可以是参数类型或参数个数的不同，但不许只有返回值类型不同。

运算符重载：

关键字 abstract 声明抽象类：用于接口部分类的实现（派生类继承抽象类时，实现完成）。抽象类包含抽象方法，抽象方法可被派生类实现。

抽象类规则：

1.不能创建抽象类的实例
2.不能在抽象类外定义抽象方法
3.不能把抽象类声明为sealed（类前带关键字sealed代表该类是密封类，不能被继承）
关键字virtual声明虚方法:用于方法在继承类中的实现（在不同的继承类中有不同的实现）。

抽象类和虚方法共同实现动态多态性。

注：继承类中的重写虚函数需要声明关键字 override，在方法参数传入中写（类名 形参名）例如 public void CallArea(Shape sh)，意思是传入一个 shape 类型的类。
 
 */

/*
 
virtual 和 abstract
virtual和abstract都是用来修饰父类的，通过覆盖父类的定义，让子类重新定义。

 1.virtual修饰的方法必须有实现（哪怕是仅仅添加一对大括号),而abstract修饰的方法一定不能实现。
 2.virtual可以被子类重写，而abstract必须被子类重写。
 3.如果类成员被abstract修饰，则该类前必须添加abstract，因为只有抽象类才可以有抽象方法。
 4.无法创建abstract类的实例，只能被继承无法实例化。
重载和重写
重载(overload)是提供了一种机制, 相同函数名通过不同的返回值类型以及参数来表来区分的机制。

见：函数重载

重写(override)是用于重写基类的虚方法,这样在派生类中提供一个新的方法。

见：动态多态性
 
 */

/*
 
抽象方法和虚方法的区别

 1.虚方法必须有实现部分，抽象方法没有提供实现部分，抽象方法是一种强制派生类覆盖的方法，否则派生类将不能被实例化。
 2.抽象方法只能在抽象类中声明，虚方法不是。如果类包含抽象方法，那么该类也是抽象的，也必须声明类是抽象的。
 3.抽象方法必须在派生类中重写，这一点和接口类似，虚方法不需要再派生类中重写。
简单说，抽象方法是需要子类去实现的。虚方法是已经实现了的，可以被子类覆盖，也可以不覆盖，取决于需求。

抽象方法和虚方法都可以供派生类重写。

 */